/*
 * Copyright (c) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import React, {useCallback, useRef, useState} from 'react';
import {
  View,
  Text,
  TouchableOpacity,
  Image,
  StyleSheet,
  Animated,
  Dimensions,
  Platform,
  PermissionsAndroid,
} from 'react-native';
import {useNavigation, useFocusEffect} from '@react-navigation/native';
import {useBreakpointValue} from '@hadss/react_native_adaptive_layout';
import {Camera} from '@react-native-oh-tpl/react-native-camera-kit';
import {launchImageLibrary} from '@react-native-ohos/react-native-image-picker';
import {CameraRoll} from '@react-native-camera-roll/camera-roll';
import {QRreader} from '@react-native-ohos/react-native-qr-decode-image-camera';
import jsQR from 'jsqr';
import jpeg from 'jpeg-js';
const PNG = require('pngjs/browser').PNG;
import {Buffer} from 'buffer';
import AvoidContainer from '../../components/AvoidContainer/AvoidContainer';

const CLOSE_ICON = require('../../../assets/pic/ic_camera_masterai_close.svg');
type Position = {
  topLeftCorner?: {x: number; y: number};
  topRightCorner?: {x: number; y: number};
  bottomLeftCorner?: {x: number; y: number};
  bottomRightCorner?: {x: number; y: number};
  center?: {x: number; y: number};
};

type Asset = {
  base64?: string;
  width?: number;
  height?: number;
  type?: string;
  originalPath?: string;
  uri?: string;
};

const Page = (): JSX.Element => {
  const navigation = useNavigation();
  const {width, height} = Dimensions.get('window');
  const [cameraLayout, setCameraLayout] = useState<{x: number; y: number; width: number; height: number} | null>(null);

  const [codes, setCodes] = useState<
    {
      value: string;
      format?: string;
      position?: Position;
      positionNormalized?: Position;
    }[]
  >([]);

  const [camKey, setCamKey] = useState<number>(0);
  const [scanEnabled, setScanEnabled] = useState<boolean>(true);
  const closeBtnStyle = useBreakpointValue({
    base: {top: 16, left: 16, width: 28, height: 28},
    sm: {top: 16, left: 16, width: 28, height: 28},
    md: {top: 20, left: 20, width: 32, height: 32},
    lg: {top: 24, left: 24, width: 36, height: 36},
  });

  const onReadCode = useCallback((event: {nativeEvent?: {codeStringValue?: string; codeFormat?: string}}) => {
    const value = event?.nativeEvent?.codeStringValue;
    const format = event?.nativeEvent?.codeFormat;
    // 当前该库实时扫码后不支持返回位置信息
    if (!value) {
      return;
    }
    setCodes((prev) => (prev.some((c) => c.value === value) ? prev : [...prev, {value, format}]));
    setScanEnabled(false);
  }, []);

  const onRescan = useCallback(() => {
    setScanEnabled(true);
    setCamKey((k) => k + 1);
    setCodes([]);
  }, []);

  const didMountRef = useRef(false);
  useFocusEffect(
    useCallback(() => {
      if (didMountRef.current) {
        onRescan();
      } else {
        didMountRef.current = true;
      }
      return () => {};
    }, [onRescan]),
  );

  const onPickFromGallery = useCallback(() => {
    const ensurePermission = async (): Promise<boolean> => {
      return true;
    };

    const addResult = (value?: string, format?: string, position?: Position, positionNormalized?: Position): void => {
      if (!value) {
        return;
      }
      setCodes((prev) =>
        prev.some((c) => c.value === value) ? prev : [{value, format, position, positionNormalized}, ...prev],
      );
      setScanEnabled(false);
    };

    const decodeWithJsQR = (
      asset: Asset,
    ): {value?: string; format?: string; position?: Position; positionNormalized?: Position} => {
      if (!asset?.base64 || !asset?.width || !asset?.height) {
        return {};
      }
      const buffer = Buffer.from(asset.base64, 'base64');
      let imageBuffer: Uint8ClampedArray | undefined;
      if (asset.type === 'image/jpeg') {
        const decoded = jpeg.decode(buffer, {useTArray: true});
        imageBuffer = Uint8ClampedArray.from(decoded.data);
      } else if (asset.type === 'image/png') {
        const decoded = PNG.sync.read(buffer);
        imageBuffer = Uint8ClampedArray.from(decoded.data);
      }
      if (!imageBuffer) {
        return {};
      }
      const code = jsQR(imageBuffer, asset.width, asset.height);
      const value = code?.data;
      const format = code ? 'qr' : undefined;
      const position = code?.location;
      if (!code?.location) {
        return {value, format};
      }
      const tl = code.location.topLeftCorner;
      const tr = code.location.topRightCorner;
      const bl = code.location.bottomLeftCorner;
      const br = code.location.bottomRightCorner;
      const cx = (tl.x + tr.x + bl.x + br.x) / 4 / asset.width;
      const cy = (tl.y + tr.y + bl.y + br.y) / 4 / asset.height;
      const positionNormalized = {
        topLeftCorner: {x: tl.x / asset.width, y: tl.y / asset.height},
        topRightCorner: {x: tr.x / asset.width, y: tr.y / asset.height},
        bottomLeftCorner: {x: bl.x / asset.width, y: bl.y / asset.height},
        bottomRightCorner: {x: br.x / asset.width, y: br.y / asset.height},
        center: {x: cx, y: cy},
      };
      return {value, format, position, positionNormalized};
    };

    const decodeAsset = async (
      asset: Asset,
    ): Promise<{value?: string; format?: string; position?: Position; positionNormalized?: Position}> => {
      const originalPath = asset?.originalPath || asset?.uri;
      if (!originalPath) {
        return {};
      }
      const path = {uri: originalPath as string};
      const res = await QRreader(path);
      let value = res?.[0]?.originalValue || res?.[0]?.data;
      let format: string | undefined = res?.[0]?.scanType || 'qr';
      let position: Position | undefined;
      let positionNormalized: Position | undefined;
      if (!value) {
        const jsqrRes = decodeWithJsQR(asset);
        value = jsqrRes.value;
        format = jsqrRes.format || format;
        position = jsqrRes.position;
        positionNormalized = jsqrRes.positionNormalized;
      }
      return {value, format, position, positionNormalized};
    };

    const tryPicker = async (): Promise<void> => {
      launchImageLibrary({mediaType: 'photo', selectionLimit: 1, includeBase64: true}, async (data) => {
        try {
          const asset = data?.assets?.[0];
          if (!asset) {
            return;
          }
          const res = await decodeAsset(asset);
          addResult(res.value, res.format, res.position, res.positionNormalized);
        } catch (e) {}
      });
    };

    const tryCameraRoll = async (): Promise<void> => {
      try {
        const photos = await CameraRoll.getPhotos({first: 1, assetType: 'Photos'});
        const uri = photos?.edges?.[0]?.node?.image?.uri;
        if (!uri) {
          return;
        }
        const res = await QRreader({uri});
        const value = res?.[0]?.originalValue || res?.[0]?.data;
        const format: string | undefined = res?.[0]?.scanType || 'qr';
        if (value) {
          setCodes((prev) => (prev.some((c) => c.value === value) ? prev : [{value, format}, ...prev]));
          setSelectedIndex(0);
          setScanEnabled(false);
        }
      } catch {
        // ignore
      }
    };

    ensurePermission().then(async (granted) => {
      if (!granted) {
        return;
      }
      try {
        if (typeof launchImageLibrary === 'function') {
          await tryPicker();
        } else {
          await tryCameraRoll();
        }
      } catch {
        await tryCameraRoll();
      }
    });
  }, []);

  return (
    <AvoidContainer>
      <View style={styles.container}>
        <View style={{flex: 1}} onLayout={(e): void => setCameraLayout(e.nativeEvent.layout)}>
          <Camera
            key={camKey}
            scanBarcode={scanEnabled}
            showFrame={true}
            frameColor={'#FFD54F'}
            laserColor={'#FF5252'}
            onReadCode={onReadCode}
            ratioOverlay={'16:9'}
            style={{width: '100%', height: '100%'}}
          />
        </View>

        <TouchableOpacity style={[styles.closeBtn, closeBtnStyle]} onPress={(): void => navigation.goBack()}>
          <Image source={CLOSE_ICON} style={{width: closeBtnStyle?.width, height: closeBtnStyle?.height}} />
        </TouchableOpacity>

        <View style={[styles.bottomBar, {width}]}>
          <TouchableOpacity style={styles.bottomBtn} onPress={onRescan}>
            <Text style={styles.bottomText}>重扫</Text>
          </TouchableOpacity>
          <TouchableOpacity style={styles.bottomBtn} onPress={onPickFromGallery}>
            <Text style={styles.bottomText}>图库</Text>
          </TouchableOpacity>
        </View>

        {codes.length > 0 && (
          <View style={StyleSheet.absoluteFillObject} pointerEvents="box-none">
            {codes.map((c, i) => {
              const cx = c.positionNormalized?.center?.x;
              const cy = c.positionNormalized?.center?.y;
              const baseW = cameraLayout?.width ?? width;
              const baseH = cameraLayout?.height ?? height;
              const baseX = cameraLayout?.x ?? 0;
              const baseY = cameraLayout?.y ?? 0;
              let left = baseX + baseW * 0.5 - 16;
              let top = baseY + baseH * 0.5 - 16;
              if (typeof cx === 'number' && typeof cy === 'number') {
                left = baseX + cx * baseW - 16;
                top = baseY + cy * baseH - 16;
              } else {
                // Fallback: stack arrows vertically at right side if no position
                left = baseX + baseW - 56;
                top = baseY + baseH - 160 - i * 44;
              }
              return (
                <TouchableOpacity
                  key={`${c.value}-${i}`}
                  style={[styles.arrowCircle, {left, top}]}
                  onPress={(): void =>
                    navigation.navigate(
                      'codeDetail' as never,
                      {
                        value: c.value,
                        format: c.format,
                        position: c.position,
                        positionNormalized: c.positionNormalized,
                      } as never,
                    )
                  }>
                  <Text style={styles.arrowIcon}>›</Text>
                </TouchableOpacity>
              );
            })}
          </View>
        )}

        {false}
      </View>
    </AvoidContainer>
  );
};

const styles = StyleSheet.create({
  container: {flex: 1, backgroundColor: '#000'},
  closeBtn: {position: 'absolute', zIndex: 10},
  bottomBar: {
    position: 'absolute',
    bottom: 24,
    left: 0,
    flexDirection: 'row',
    justifyContent: 'center',
    columnGap: 24,
  },
  bottomBtn: {
    paddingHorizontal: 18,
    paddingVertical: 10,
    borderRadius: 20,
    backgroundColor: 'rgba(0,0,0,0.5)',
    borderWidth: 1,
    borderColor: 'rgba(255,255,255,0.2)',
  },
  bottomText: {color: '#fff', fontSize: 14},
  codesContainer: {},
  codeItem: {},
  codeText: {},
  arrow: {},
  arrowCircle: {
    position: 'absolute',
    width: 32,
    height: 32,
    borderRadius: 16,
    backgroundColor: '#00C853',
    alignItems: 'center',
    justifyContent: 'center',
    borderWidth: 1,
    borderColor: 'rgba(255,255,255,0.25)',
  },
  arrowIcon: {color: '#fff', fontSize: 20},
  card: {},
  cardTitle: {},
  cardValue: {},
});

export default Page;
